package com.ruoyi.game.core;

import com.ruoyi.game.core.card.BaseCardType;
import com.ruoyi.game.core.card.BasePoker;
import com.ruoyi.game.core.card.CardTypeManager;
import com.ruoyi.game.core.status.LiangZhuInfo;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.ruoyi.game.core.card.BasePoker.toCardString;

/**
 * 托管/机器人出牌策略类（逻辑入口）
 */
@Slf4j
public class GameSetRobotPos {

    public static List<Integer> aiChooseLiangZhu1(GameSetPos pos, GameSetCore set) {
        List<Integer> handCards = pos.getHandCards();
        int zhuValue = set.getZhuValue();

        log.info("[AI-LiangZhu1] 玩家 {} 托管亮主，手牌：{}", pos.getPlayerId(),
                handCards.stream().map(BasePoker::getCardDescription).collect(Collectors.joining(", ")));
        return handCards.stream()
                .filter(card -> BasePoker.getCardValueEx(card) == zhuValue)
                .limit(1)
                .collect(Collectors.toList());
    }

    public static List<Integer> aiChooseLiangZhu2(GameSetPos pos, GameSetCore set) {
        List<Integer> handCards = pos.getHandCards();
        int zhuValue = set.getZhuValue();

        log.info("[AI-LiangZhu2/Fanzhu] 玩家 {} 托管亮主，手牌：{}", pos.getPlayerId(),
                BasePoker.toCardString(handCards));

        List<Integer> bigWangs = handCards.stream()
                .filter(BasePoker::isDaWang)
                .collect(Collectors.toList());

        List<Integer> smallWangs = handCards.stream()
                .filter(BasePoker::isXiaoWang)
                .collect(Collectors.toList());

        List<Integer> zhuCards = handCards.stream()
                .filter(card -> BasePoker.getCardValueEx(card) == zhuValue)
                .collect(Collectors.toList());

        // ✅ 优先：两个大王 + 主牌
        if (bigWangs.size() >= 2 && !zhuCards.isEmpty()) {
            List<Integer> result = new ArrayList<>(bigWangs.subList(0, 2));
            result.add(zhuCards.get(0));
            return result;
        }

        // ✅ 其次：两个小王 + 主牌
        if (smallWangs.size() >= 2 && !zhuCards.isEmpty()) {
            List<Integer> result = new ArrayList<>(smallWangs.subList(0, 2));
            result.add(zhuCards.get(0));
            return result;
        }

        // ✅ 再次：两张同花色的主牌
        Map<Integer, List<Integer>> zhuByColor = zhuCards.stream()
                .collect(Collectors.groupingBy(BasePoker::getCardColor));

        for (List<Integer> sameColor : zhuByColor.values()) {
            if (sameColor.size() >= 2) {
                return sameColor.subList(0, 2);
            }
        }

        // 否则返回空
        log.warn("[AI-LiangZhu2/Fanzhu] 玩家 {} 无法亮主，未找到合适组合", pos.getPlayerId());
        return Collections.emptyList();
    }


    public static List<Integer> aiChooseZiBao(GameSetPos pos, GameSetCore set) {
        List<Integer> handCards = pos.getHandCards();
        int zhuValue = set.getZhuValue();
        LiangZhuInfo liangZhuInfo = pos.getLiangZhuInfo();
        Integer currentLiangZhuColor = liangZhuInfo != null ? BasePoker.getCardColor(liangZhuInfo.getZhuCards().get(0)) : -1;

        log.info("[AI-ZiBao] 玩家 {} 托管自保，手牌：{}", pos.getPlayerId(),
                handCards.stream().map(BasePoker::getCardDescription).collect(Collectors.joining(", ")));

        // 过滤出主牌，并且与当前亮主的花色相同
        List<Integer> sameColorMainCards = handCards.stream()
                .filter(card -> BasePoker.getCardValueEx(card) == zhuValue) // 过滤出主牌
                .filter(card -> BasePoker.getCardColor(card) == currentLiangZhuColor) // 过滤出符合亮主花色的主牌
                .collect(Collectors.toList());

        // 如果有两张主牌并且符合花色要求，选择两张
        if (sameColorMainCards.size() >= 2) {
            return sameColorMainCards.subList(0, 2); // 返回两张主牌
        }

        // 如果没有两张主牌，检查是否有两个小王+主
        long smallWangCount = handCards.stream().filter(card -> BasePoker.getCardValueEx(card) == 17).count();
        if (smallWangCount >= 2) {
            List<Integer> result = handCards.stream()
                    .filter(card -> BasePoker.getCardValueEx(card) == 17) // 小王
                    .limit(2)
                    .collect(Collectors.toList());
            result.addAll(handCards.stream()
                    .filter(card -> BasePoker.getCardValueEx(card) == zhuValue) // 主牌
                    .limit(1)
                    .collect(Collectors.toList()));
            return result; // 返回两个小王+主
        }

        // 如果没有两个小王，检查是否有两个大王+主
        long bigWangCount = handCards.stream().filter(card -> BasePoker.getCardValueEx(card) == 18).count();
        if (bigWangCount >= 2) {
            List<Integer> result = handCards.stream()
                    .filter(card -> BasePoker.getCardValueEx(card) == 18) // 大王
                    .limit(2)
                    .collect(Collectors.toList());
            result.addAll(handCards.stream()
                    .filter(card -> BasePoker.getCardValueEx(card) == zhuValue) // 主牌
                    .limit(1)
                    .collect(Collectors.toList()));
            return result; // 返回两个大王+主
        }

        return Collections.emptyList(); // 没有合适的选择，返回空
    }

    public static List<Integer> aiChooseZiFan(GameSetPos pos, GameSetCore set) {
        List<Integer> handCards = pos.getHandCards();
        int zhuValue = set.getZhuValue();
        LiangZhuInfo liangZhuInfo = pos.getLiangZhuInfo();
        Integer currentLiangZhuColor = liangZhuInfo != null ? BasePoker.getCardColor(liangZhuInfo.getZhuCards().get(0)) : -1;

        log.info("[AI-ZiFan] 玩家 {} 托管自反，手牌：{}", pos.getPlayerId(),
                handCards.stream().map(BasePoker::getCardDescription).collect(Collectors.joining(", ")));

        // 过滤出主牌，并且与当前亮主的花色不同
        List<Integer> differentColorMainCards = handCards.stream()
                .filter(card -> BasePoker.getCardValueEx(card) == zhuValue) // 过滤出主牌
                .filter(card -> BasePoker.getCardColor(card) != currentLiangZhuColor) // 过滤出与亮主花色不同的主牌
                .collect(Collectors.toList());


        // 如果有两张主牌且花色相同，选择两张
        if (differentColorMainCards.size() >= 2) {
            // 分组按花色
            Map<Integer, List<Integer>> groupedByColor = differentColorMainCards.stream()
                    .collect(Collectors.groupingBy(BasePoker::getCardColor));

            for (List<Integer> sameColorCards : groupedByColor.values()) {
                if (sameColorCards.size() >= 2) {
                    return sameColorCards.subList(0, 2); // 返回两张花色相同的主牌
                }
            }
        }

        // 如果没有两张主牌，检查是否有两个小王+主
        long smallWangCount = handCards.stream().filter(card -> BasePoker.getCardValueEx(card) == 17).count();
        if (smallWangCount >= 2) {
            List<Integer> result = handCards.stream()
                    .filter(card -> BasePoker.getCardValueEx(card) == 17) // 小王
                    .limit(2)
                    .collect(Collectors.toList());
            result.addAll(handCards.stream()
                    .filter(card -> BasePoker.getCardValueEx(card) == zhuValue) // 主牌
                    .limit(1)
                    .collect(Collectors.toList()));
            return result; // 返回两个小王+主
        }

        // 如果没有两个小王，检查是否有两个大王+主
        long bigWangCount = handCards.stream().filter(card -> BasePoker.getCardValueEx(card) == 18).count();
        if (bigWangCount >= 2) {
            List<Integer> result = handCards.stream()
                    .filter(card -> BasePoker.getCardValueEx(card) == 18) // 大王
                    .limit(2)
                    .collect(Collectors.toList());
            result.addAll(handCards.stream()
                    .filter(card -> BasePoker.getCardValueEx(card) == zhuValue) // 主牌
                    .limit(1)
                    .collect(Collectors.toList()));
            return result; // 返回两个大王+主
        }

        return Collections.emptyList(); // 没有合适的选择，返回空
    }

    /**
     * 【扣底】策略：默认取手牌后8张（必须有28张才认为是庄家）
     */
    public static List<Integer> aiChooseKouDiCards(GameSetPos pos) {
        List<Integer> hand = new ArrayList<>(pos.getHandCards());
        long playerId = pos.getPlayerId();

        if (hand.size() != 28) {
            log.warn("[AI-KouDi] 玩家 {} 扣底失败，手牌不是 28 张，而是 {} 张", playerId, hand.size());
            return Collections.emptyList();
        }

        int zhuColor = pos.getGameSet().getLiangZhuInfo().getZhuColor();
        int zhuValue = pos.getGameSet().getZhuValue();

        log.info("[AI-KouDi] 玩家 {} 托管扣底，主花色={}，主值={}，当前手牌={}",
                playerId,
                BasePoker.PockerColorType.valueOf(zhuColor),
                zhuValue,
                toCardString(hand));

        List<Integer> result = new ArrayList<>();

        // 工具方法：按花色分类
        Map<Integer, List<Integer>> colorMap = hand.stream()
                .collect(Collectors.groupingBy(BasePoker::getCardColor));

        Predicate<Integer> isAKZhu = c -> {
            int v = BasePoker.getCardValueEx(c);
            return v == 13 || v == 14 || v == zhuValue;
        };

        // ✅ 优先级1：非主花色中的单牌，排除 A/K 和主花色的牌值
        for (int color = 0; color < 4; color++) {
            if (color == zhuColor) continue;
            List<Integer> colorCards = colorMap.getOrDefault(color, new ArrayList<>());
            Map<Integer, List<Integer>> group = colorCards.stream()
                    .collect(Collectors.groupingBy(BasePoker::getCardValueEx));

            for (List<Integer> same : group.values()) {
                if (same.size() == 1 && !isAKZhu.test(same.get(0))) {
                    result.add(same.get(0));
                    log.info("[AI-KouDi] 玩家 {} 扣底优先级1：添加非主花色单牌 {}", playerId, BasePoker.getCardDescription(same.get(0)));
                    if (result.size() == 8) return logResult(playerId, result);
                }
            }
        }

        // ✅ 优先级2：主花色中的单牌，排除 A/K
        List<Integer> zhuCards = colorMap.getOrDefault(zhuColor, new ArrayList<>());
        Map<Integer, List<Integer>> zhuGroup = zhuCards.stream()
                .collect(Collectors.groupingBy(BasePoker::getCardValueEx));
        for (List<Integer> same : zhuGroup.values()) {
            if (same.size() == 1 && !isAKZhu.test(same.get(0))) {
                result.add(same.get(0));
                log.info("[AI-KouDi] 玩家 {} 扣底优先级2：添加主花色单牌 {}", playerId, BasePoker.getCardDescription(same.get(0)));
                if (result.size() == 8) return logResult(playerId, result);
            }
        }

        // ✅ 优先级3：非主花色中的对子，从小到大
        for (int color = 0; color < 4; color++) {
            if (color == zhuColor) continue;
            List<Integer> colorCards = colorMap.getOrDefault(color, new ArrayList<>());
            Map<Integer, List<Integer>> group = colorCards.stream()
                    .collect(Collectors.groupingBy(BasePoker::getCardValueEx));

            List<List<Integer>> pairs = group.values().stream()
                    .filter(list -> list.size() == 2)
                    .sorted(Comparator.comparingInt(l -> BasePoker.getCardValueEx(l.get(0))))
                    .collect(Collectors.toList());

            for (List<Integer> pair : pairs) {
                result.addAll(pair);
                log.info("[AI-KouDi] 玩家 {} 扣底优先级3：添加对子 {}", playerId, toCardString(pair));
                if (result.size() >= 8) return logResult(playerId, result.subList(0, 8));
            }
        }

        // fallback：补足剩余
        for (Integer c : hand) {
            if (!result.contains(c)) {
                result.add(c);
                log.info("[AI-KouDi] 玩家 {} fallback：补充手牌 {}", playerId, BasePoker.getCardDescription(c));
                if (result.size() == 8) break;
            }
        }

        return logResult(playerId, result);
    }

    private static List<Integer> logResult(long playerId, List<Integer> result) {
        log.info("[AI-KouDi] 玩家 {} 扣底选择完成：{}", playerId, toCardString(result));
        return result;
    }

    /**
     * 【喊打】策略：找最大单张
     */
    public static int aiChooseHanDaCard(GameSetPos pos) {
        List<Integer> hand = pos.getHandCards();
        if (hand.isEmpty()) {
            log.warn("[AI-HanDa] 玩家 {} 托管喊打失败：手牌为空", pos.getPlayerId());
            return -1;
        }

        // 合并手牌和扣底牌
        List<Integer> combinedCards = new ArrayList<>(hand);
        combinedCards.addAll(pos.getGameSet().getKouPaiList());
        log.info("[AI-HanDa] 玩家 {} 托管喊打，当前手牌+扣底牌：{}", pos.getPlayerId(), toCardString(combinedCards));

        // 统计完整卡牌（花色+点数）的频次
        Map<Integer, Long> freqMap = combinedCards.stream()
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        log.info("[AI-HanDa] 玩家 {} 托管喊打，完整牌频次：{}", pos.getPlayerId(), freqMap);

        // 找出只出现一次的整张牌，按点数从大到小排序
        List<Integer> singles = combinedCards.stream()
                .filter(c -> freqMap.get(c) == 1)
                .sorted(Comparator.comparingInt(BasePoker::getCardValueEx).reversed())
                .collect(Collectors.toList());

        log.info("[AI-HanDa] 玩家 {} 托管喊打，可用单张列表：{}", pos.getPlayerId(), toCardString(singles));

        // 如果找到且仅有一张单牌，选择这张牌
        int result = singles.size() >= 1 ? singles.get(0) : -1;
        if (result == -1) {
            log.info("[AI-HanDa] 玩家 {} 托管喊打未找到合适的单牌", pos.getPlayerId());
        } else {
            log.info("[AI-HanDa] 玩家 {} 托管喊打选择卡牌：{}", pos.getPlayerId(), BasePoker.getCardDescription(result));
        }

        return result;
    }

    /**
     * 【出牌】策略（placeholder，实际需要接入旧项目判断）
     * 当前版本：打第一张
     */
    public static List<Integer> aiChoosePlayCard(GameSetPos pos, GameRoundCore round) {
        List<Integer> hand = new ArrayList<>(pos.getHandCards());
        log.info("[AI-] 玩家 {} 当前手牌：{}", pos.getPlayerId(), toCardString(hand));
        if (round == null || hand.isEmpty()) return Collections.emptyList();

        boolean isFirstOut = round.isFirstOut();  // 是否是首出

        if (isFirstOut) {
            return tryFirstOutCard(pos);  // 模拟出任意合法牌型
        } else {
            return tryFollowCard(pos, round);  // 跟牌逻辑：压住或合理跟
        }
    }

    public static List<Integer> tryFirstOutCard(GameSetPos pos) {
        for (BaseCardType cardType : CardTypeManager.getCardTypes()) {
            log.info("[AI-] 检查牌型-首出：{}", cardType.getName());
            List<Integer> result = cardType.firstAutoOut(pos);
            if (!result.isEmpty()) return result;
        }
        return Collections.emptyList();
    }

    public static List<Integer> tryFollowCard(GameSetPos pos, GameRoundCore round) {
        for (BaseCardType cardType : CardTypeManager.getCardTypes()) {
            log.info("[AI-] 检查牌型-跟牌：{}", cardType.getName());
            List<Integer> result = cardType.followAutoOut(pos, round);
            if (!result.isEmpty()) return result;
        }
        return Collections.emptyList();
    }

}
